#pragma once

#include <deque>
#include <memory>
#include <unordered_set>
#include <functional>
#include <vector>
#include <cstdint>

namespace xyu
{
    namespace net
    {
        using EntryPtr = std::shared_ptr<void>;
        using WheelEntry = std::unordered_set<EntryPtr>;
        using Wheel = std::deque<WheelEntry>;
        using Wheels = std::vector<Wheel>;
        using Func = std::function<void()>;
        
        constexpr int MinuteType = 60;
        constexpr int HourType = 3600;
        constexpr int DayType = HourType * 24;
        class CallbackEntry
        {
        public:
            CallbackEntry(const Func& cb) : cb_(cb){}
            ~CallbackEntry()
            {
                if (cb_)
                {
                    cb_();
                }
            }
        private:
            Func cb_;
        };

        using CallbackEntryPtr = std::shared_ptr<CallbackEntry>;
        enum TimingType
        {
            Second = 0,
            Minute,
            Hour,
            Day
        };

        class TimingWheel
        {
        public:
            TimingWheel();
            ~TimingWheel();

            void InsertEntry(uint32_t delay, EntryPtr entry);
            void OnTimer(int64_t now);
            void PopUp(Wheel& pop);
            void RunAfter(double delay, const Func& cb);
            void RunAfter(double delay, Func&& cb);
            void RunEvery(double interval,const Func& cb);
            void RunEvery(double interval, Func&& cb);
        private:
            void InsertSecondEntry(uint32_t delay, EntryPtr entry);
            void InsertMinuteEntry(uint32_t delay, EntryPtr entry);
            void InsertHourEntry(uint32_t delay, EntryPtr entry);
            void InsertDayEntry(uint32_t delay, EntryPtr entry);

            Wheels wheels_; // 轮
            int64_t last_ts_ = 0;   // 上次检测
            uint64_t tick_ = 0; // 检测次数
        };
    }   /* namespace net */
}   /* namespace xyu */
